package utils

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"github.com/dgrijalva/jwt-go"
	"io/ioutil"
	"my_iris/global"
	"net/http"
	"regexp"
	"strings"
	"time"
	"unicode/utf8"
)

var jwtConf = global.JwtConfig{
	Secret: "abc",
	TTL:    3600,
}

func NewJwtTokenString(c jwt.MapClaims) (jwtString string, err error) {
	claims := jwt.MapClaims{
		//"aud": "",
		"exp": time.Now().Add(jwtConf.TTL * time.Second).Unix(),
		"iat": time.Now().Unix(),
		"iss": "ltconsult.cn",
		//"jti": "",
		"nbf": time.Now().Unix(),
		//"sub": "",
	}
	for k, v := range c {
		claims[k] = v
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	jwtString, err = token.SignedString([]byte(jwtConf.Secret))
	return
}

// *************************************** 分割线 ***********************************************

// 我国现行的身份证号码有两种标准：GB11643-1989、GB11643-1999：
//
// GB11643-1989为一代身份证，从左至右分别为：
//  ------------------------------------------------------------
//  | 6位行政区域代码 | 6位出生年日期（不含世纪数）| 3位顺序码 |
//  ------------------------------------------------------------
//
// GB11643-1999为二代身份证，从左至右分别为：
//  ------------------------------------------------------------
//  | 6位行政区域代码 |  8位出生日期 |  3位顺序码 |  1位检验码 |
//  ------------------------------------------------------------

var (
	// 校验位对应的规则。
	gb11643Map = []byte{'1', '0', 'x', '9', '8', '7', '6', '5', '4', '3', '2'}

	// 前17位号码对应的权值，为一个固定数组。可由gb11643_test.getWeight()计算得到。
	gb11643Weight = []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
)

// 判断一个身份证是否符合gb11643标准。
// 若是15位则当作一代身份证，仅简单地判断各位是否都是数字；
// 若是18位则当作二代身份证，会计算校验位是否正确；
// 其它位数都返回false。
func IsGb11643(val interface{}) bool {
	switch v := val.(type) {
	case string:
		return IsGb11643Bytes([]byte(v))
	case []byte:
		return IsGb11643Bytes(v)
	case []rune:
		return IsGb11643Bytes([]byte(string(v)))
	default:
		return false
	}
}

// 判断一个身份证是否符合gb11643标准。
func IsGb11643Bytes(val []byte) bool {
	if len(val) == 15 {
		// 15位，只检测是否包含非数字字符。
		for i := 0; i < 15; i++ {
			if val[i] < '0' || val[i] > '9' {
				return false
			}
		} // end for
		return true
	}

	if len(val) != 18 {
		return false
	}

	sum := 0
	for i := 0; i < 17; i++ {
		sum += (gb11643Weight[i] * int((val[i] - '0')))
	}
	if val[17] == 'X' {
		val[17] = 'x'
	}
	return gb11643Map[sum%11] == val[17]
}

// 是否是有效的18位身份证号
func IsValidIDNumber(val string) bool {
	if len(val) != 18 {
		return false
	}
	return IsGb11643(val)
}

// *************************************** 分割线 ***********************************************

func MD5(str []byte) (md5Str string) {
	h := md5.New()
	h.Write(str)
	md5Str = hex.EncodeToString(h.Sum(nil))
	return
}

func IsValidEmail(val string) bool {
	val = strings.TrimSpace(val)
	reg := regexp.MustCompile(`^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$`)
	return reg.MatchString(val)
}

func IsValidPhoneNumber(val string) bool {
	val = strings.TrimSpace(val)
	reg := regexp.MustCompile(`^1[0-9]{10}$`)
	return reg.MatchString(val)
}

func InArrayString(str string, arr []string) bool {
	for _, v := range arr {
		if str == v {
			return true
		}
	}
	return false
}

type IpToPosition struct {
	Status    string `json:"status"`    // 值为0或1,0表示失败；1表示成功
	Info      string `json:"info"`      // 返回状态说明，status为0时，info返回错误原因，否则返回“OK”。
	InfoCode  string `json:"info_code"` // 返回状态说明,10000代表正确,详情参阅info状态表
	Province  string `json:"province"`  // 若为直辖市则显示直辖市名称；如果在局域网 IP网段内，则返回“局域网”；非法IP以及国外IP则返回空
	City      string `json:"city"`      // 若为直辖市则显示直辖市名称；如果为局域网网段内IP或者非法IP或国外IP，则返回空
	AdCode    string `json:"ad_code"`   // 城市的adcode编码
	Rectangle string `json:"rectangle"` // 所在城市矩形区域范围: 所在城市范围的左下右上对标对
}

func GetPositionByIP(ip string) (result IpToPosition) {
	url := "https://restapi.amap.com/v3/ip?key=196c06a4077af7228dc5c51e34c70a61&ip=" + ip
	resp, _ := http.Get(url)
	result = IpToPosition{}
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)
	_ = json.Unmarshal(body, &result)
	if result.Province == "" || result.Province == "局域网" {
		result.Province = "上海"
	} else {
		result.Province = strings.TrimSuffix(result.Province, "省")
		result.Province = strings.TrimSuffix(result.Province, "市")
	}
	if result.City == "" {
		result.City = "上海"
	} else {
		result.City = strings.TrimSuffix(result.City, "市")
	}
	return
}

// 获取一个月中所有天的零点
func GetMonthDays(d time.Time) (days []time.Time) {
	last := GetLastDayOfMonth(d)
	day := GetFirstDayOfMonth(d)
	days = append(days, day)
	for day != last {
		day = day.AddDate(0, 0, 1)
		days = append(days, day)
	}
	return
}

//获取传入的时间所在月份的第一天，即某月第一天的0点。如传入time.Now(), 返回当前月份的第一天0点时间。
func GetFirstDayOfMonth(d time.Time) time.Time {
	d = d.AddDate(0, 0, -d.Day()+1)
	return GetZeroTime(d)
}

//获取传入的时间所在月份的最后一天，即某月最后一天的0点。如传入time.Now(), 返回当前月份的最后一天0点时间。
func GetLastDayOfMonth(d time.Time) time.Time {
	d = d.AddDate(0, 1, -d.Day())
	return GetZeroTime(d)
}

//获取某一天的0点时间
func GetZeroTime(d time.Time) time.Time {
	return time.Date(d.Year(), d.Month(), d.Day(), 0, 0, 0, 0, d.Location())
}

//获取字符串长度
func GetStrLength(str string) int {
	return utf8.RuneCountInString(str)
}

//替换姓名中的部分字段为*
func ProtectUserName(name string) string {
	length := utf8.RuneCountInString(name)
	if length <= 1 {
		return name + "*"
	}
	rs := []rune(name)
	if length == 2 {
		return string(rs[0]) + "*"
	}
	return string(rs[0]) + "*" + string(rs[length-1])
}
